package com.tron.dobest.tools;

import lombok.Data;
import org.springframework.lang.Nullable;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author Tron
 * @create 2019-12-03
 */
public class TronTool {

    /**
     * -----------------------------------------时间-----------------------------------------
     */

    /**
     * 国际UTC, Universal Time Coordinated 与 格林尼治平均时(GMT, Greenwich Mean Time)一样
     * 北京时区是东八区，领先UTC八个小时
     * @param localDateTime
     * @return
     */

    /**
     * localDateTime 转 Date
     *
     * @param localDateTime
     * @return Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.toInstant(ZoneOffset.ofHours(8)));
    }

    /**
     * Date 转 LocalDateTime
     *
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * Date 转 Timestamp
     *
     * @param date
     * @return Timestamp
     */
    private static Timestamp toTimestamp(Date date) {
        return dateOrLocalDateTimeToTimeStamp(date);
    }

    /**
     * LocalDateTime 转 Timestamp
     *
     * @param localDateTime
     * @return Timestamp
     */
    private static Timestamp toTimestamp(LocalDateTime localDateTime) {
        return dateOrLocalDateTimeToTimeStamp(localDateTime);
    }

    /**
     * 数据存储时间转换
     *
     * @param o
     * @return Timestamp
     */
    public static Timestamp dateOrLocalDateTimeToTimeStamp(Object o) {
        if (o instanceof Date) {
            Date date = (Date) o;
            return Timestamp.from(date.toInstant());
        } else {
            LocalDateTime localDateTime = (LocalDateTime) o;
            return Timestamp.valueOf(localDateTime);
        }
    }


    /**
     * -----------------------------------------字符串-----------------------------------------
     */

    /**
     * 判空
     *
     * @param str
     * @return
     */
    public static boolean isEmptyString(Object str) {
        return (str == null || "".equals(str));
    }

    /**
     * 判断字符串有非空字符内容
     *
     * @param str
     * @return Boolean
     */
    private static boolean hasLength(CharSequence str) {
        return (str != null && str.length() > 0);
    }

    /**
     * 替换所有位置的匹配内容
     *
     * @param inString
     * @param oldPattern
     * @param newPattern
     * @return
     */
    public static String replaceString(String inString, String oldPattern, @Nullable String newPattern) {
        if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) {
            return inString;
        }
        int index = inString.indexOf(oldPattern);
        if (index == -1) {
            return inString;
        }

        int capacity = inString.length();
        if (newPattern.length() > oldPattern.length()) {
            capacity += 16;
        }
        StringBuilder sb = new StringBuilder(capacity);
        int pos = 0;
        int patLen = oldPattern.length();
        while (index >= 0) {
            sb.append(inString.substring(pos, index));
            sb.append(newPattern);
            pos = index + patLen;
            index = inString.indexOf(oldPattern, pos);
        }
        sb.append(inString.substring(pos));
        return sb.toString();
    }

    /**
     * 删除指定位置的内容
     *
     * @param str
     * @param pattern
     * @return
     */
    public static String deleteString(String str, String pattern) {
        return replaceString(str, pattern, "");
    }

    /**
     * 删除指定位置的内容，匹配起始位置和结束位置
     *
     * @param str
     * @param startWith
     * @param endWith
     * @return
     */
    public static String deleteString(String str, String startWith, String endWith) {
        if (!hasLength(str) || !hasLength(startWith) || !hasLength(endWith)) {
            return str;
        }
        int i = str.indexOf(startWith);
        int j = str.indexOf(endWith);
        int k = str.length();
        return new StringBuilder().append(str.substring(0, i)).append(str.substring(j + 1, k)).toString();
    }


    /**
     * 去除字符串中的所有特殊字符
     * @param str
     * @return
     */
    public static String filterString(String str) {
        if (!hasLength(str)) {
            return "";
        }
        String regEx="[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        String trim = m.replaceAll("").trim();
        String replace = trim.replace("\\", "");
        return replace;
    }


    /**
     * 取出指定位置的内容，如：<a>取出这里的内容</a>，可以匹配多个。
     *
     * @param startWith
     * @param endWith
     * @param str
     * @return
     */
    public static List<String> matchString(String str, String startWith, String endWith) {
        ArrayList<String> strings = new ArrayList<>();
        if (!hasLength(str) || !hasLength(startWith) || !hasLength(endWith)) {
            return strings;
        }
        Matcher matcher = Pattern.compile("(?<=" + startWith + ").*?(?=" + endWith + ")").matcher(str);
        while (matcher.find()) {
            strings.add(matcher.group());
        }
        return strings;
    }


    /**
     * -----------------------------------------反射-----------------------------------------
     */

    /**
     * 获取本类所有字段，及父类的PROTECTED字段
     *
     * @param clazz
     * @return List<String>
     */
    public static List<String> getBeanDeclaredFiledNames(Class clazz) {
        Class superclass = clazz.getSuperclass();
        ArrayList<String> list = new ArrayList<>();
        list.addAll(getBeanFieldNames(superclass, e -> e == Modifier.PROTECTED));
        list.addAll(getBeanFieldNames(clazz, null));
        return list;
    }

    /**
     * 获取类的字段属性名
     *
     * @param clazz
     * @param predicate 条件传null
     * @return List<String>
     */
    public static List<String> getBeanFieldNames(Class clazz, Predicate<Integer> predicate) {
        ArrayList<String> list = new ArrayList<>();
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (predicate != null) {
                if (predicate.test(field.getModifiers())) {
                    list.add(field.getName());
                }
            } else {
                list.add(field.getName());
            }
        }
        return list;
    }


    /**
     * -----------------------------------------代理-----------------------------------------
     */

    /**
     * MethodInterceptor methodInterceptor = (a,b,c,d)->{
     * //a  Object o                  对象
     * //b  Method method             方法
     * //c  Object[] objects          方法参数
     * //d  MethodProxy methodProxy   代理
     * //todo
     * return d.invokeSuper(a,c);
     * };
     *
     * @param clazz
     * @param methodInterceptor
     * @param <T>
     * @return
     */

//    public static <T> T getProxy(Class<T> clazz, MethodInterceptor methodInterceptor) {
//        Enhancer enhancer = new Enhancer();
//        enhancer.setSuperclass(clazz);
//        enhancer.setCallback(methodInterceptor);
//        return (T) enhancer.create();
//    }


    /**
     * 获取分组数据包装集合
     */
    public static <T> ArrayList<GroupData> getGroupData(List<T> list, Function<T, String> function) {
        Map<String, List<T>> collect = list.stream().collect(groupingBy(function));
        ArrayList<GroupData> groupDataList = new ArrayList<>();
        collect.forEach((k, v) -> {
            GroupData groupData = new GroupData();
            groupData.setGroupName(k);
            groupData.setGroupItems(v);
            groupDataList.add(groupData);
        });
        return groupDataList;
    }

    @Data
    public static class GroupData {
        private String groupName;
        private List groupItems;
    }


}
